//
// Created by DengLibin on 2018/12/12 0012.
//
/**
异常接口声明:
1）为了加强程序的可读性，可以在函数声明中列出可能抛出的所有异常类型，例如：
void func() throw (A, B, C , D); //这个函数func（）能够且只能抛出类型A B C D及其子类型的异常。
2）如果在函数声明中没有包含异常接口声明，则次函数可以抛掷任何类型的异常，例如：
void func();
3）一个不抛掷任何类型异常的函数可以声明为：
void func()  throw();
4） 如果一个函数抛出了它的异常接口声明所不允许抛出的异常，unexpected函数会被调用，该函数默认行为调用terminate函数中止程序。

结论：C++编译器通过throw 来产生对象，C++编译器再执行对应的catch分支，相当于一个函数调用，把实参传递给形参。
异常的捕捉严格匹配数据类型，不支持类型自动转换，throw的是int类型则catch的必须是int类型否则不会匹配
一般我们在异常最后加入catch(...)这样能够捕获任意异常。
*/
#include <iostream>
#include <string>
using namespace std;
class MyException
{
private:
    string msg;
public:
    MyException(string & msg)
    {
        cout << "创建了异常对象" << endl;
        this->msg = msg;
    }
    string & getMsg()
    {
        return this->msg;
    }
    ~MyException()
    {
        cout <<"析构异常对象"<<endl;
    }
    MyException(const MyException & myException)
    {
        this->msg = myException.msg;
        cout <<"拷贝了异常对象"<<endl;
    }

};
///声明要抛出的异常类型(声明后只能抛该类型或者子类的异常),引用和类型不能同时用，推荐用引用
double  divide(int a, int b) throw (int, MyException &)
{
    if(b == 0)
    {
        throw b;
    }
    if(b < 0)
    {
        string msg = "除数不能小于0";
        MyException e(msg);
        throw e;
    }
    return  (double)a / (double)b;
}

void test_exception()
{
    try{
        divide(1,-1);
    }catch (int e)
    {
        cout << "异常:"<< e<<endl;
    }catch (MyException & e)
    {
        cout << "异常:"<< e.getMsg()<<endl;
    }

}
int main17()
{
    test_exception();
    return 0;
}